home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / tile-for.1 / tile-for / tile-forth-2.1 / src / io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-14  |  10.2 KB  |  413 lines

  1. /*
  2.   C BASED FORTH-83 MULTI-TASKING IO MANAGEMENT
  3.  
  4.   Copyright (C) 1988-1990 by Mikael Patel
  5.  
  6.   Computer Aided Design Laboratory (CADLAB)
  7.   Department of Computer and Information Science
  8.   Linkoping University
  9.   S-581 83 LINKOPING
  10.   SWEDEN
  11.  
  12.   Email: mip@ida.liu.se
  13.   
  14.   Started on: 30 June 1988
  15.  
  16.   Last updated on: 26 June 1990
  17.  
  18.   Dependencies:
  19.        (cc) fcntl.h, errno.h, kernel.h, error.h, memory.h and io.h
  20.  
  21.   Description:
  22.        Handles low level access to Operating System to allow asynchronous
  23.        input and multi-tasking of Forth level processes while waiting for
  24.        buffer filling. File names are saved so that files are not reloaded. 
  25.   
  26.   Copying:
  27.        This program is free software; you can redistribute it and/or modify
  28.        it under the terms of the GNU General Public License as published by
  29.        the Free Software Foundation; either version 1, or (at your option)
  30.        any later version.
  31.  
  32.        This program is distributed in the hope that it will be useful,
  33.        but WITHOUT ANY WARRANTY; without even the implied warranty of
  34.        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  35.        GNU General Public License for more details.
  36.  
  37.        You should have received a copy of the GNU General Public License
  38.        along with this program; see the file COPYING.  If not, write to
  39.        the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  40.  
  41. */
  42.  
  43.  
  44. #include <fcntl.h>
  45. #include <errno.h>
  46. #include "kernel.h"
  47. #include "error.h"
  48. #include "memory.h"
  49. #include "io.h"
  50.  
  51.  
  52. /* EXTERNAL DEFINED IO DISPATCH ROUTINE, ENVIRONMENT ACCESS AND ERROR CODE */
  53.  
  54. extern VOID io_dispatch();
  55. extern CSTR getenv();
  56. extern INT  errno;
  57.  
  58.  
  59. /* MAXIMUM FILE AND PATH NAME STRING SIZES */
  60.  
  61. #define FILENAMESIZE 128
  62. #define PATHNAMESIZE 128
  63.  
  64.  
  65. /* INFILE BUFFERS STACK AND STACK POINTER */
  66.  
  67. #define INFSTACKSIZE 32
  68.  
  69. INFILE_BUFFER io_infstack[INFSTACKSIZE];
  70. INT io_infsp = -1;
  71.  
  72.  
  73. /* OUTFILE AND ERROR FILE VARIABLES */
  74.  
  75. FILE *io_outf;
  76. FILE *io_errf;
  77.  
  78.  
  79. /* STACK OF NAMES OF LOADED FILE */
  80.  
  81. #define INFILESSIZE 64
  82.  
  83. static CSTR infiles[INFILESSIZE];
  84. static INT infsp = -1;
  85.  
  86.  
  87. /* STACK OF FILE SEARCH PATHS */
  88.  
  89. #define PATHSSIZE 32
  90.  
  91. static CSTR paths[PATHSSIZE];
  92. static INT psp = -1;
  93.  
  94.  
  95. /* IO MANAGEMENT DEFINITONS */
  96.  
  97. INT io_path(pname, pos)
  98.     CSTR pname;            /* Pointer to path name */
  99.     INT pos;            /* Position to append */
  100. {
  101.     CHAR pathname[PATHNAMESIZE];    
  102.     INT plen = strlen(pname);
  103.     INT i;
  104.  
  105.     /* Check for null path. Dont add these */
  106.     if (plen == 0) return IO_NO_ERROR;
  107.  
  108.     /* Check if the path name is an environment variable */
  109.     if (pname[0] == '$') {
  110.  
  111.     /* Fetch the environment variables value */
  112.     char *paths = (char *) getenv((char *) pname + 1);
  113.  
  114.     /* If paths are available recursivly add them to the path list */
  115.     if (paths) {
  116.         while (*paths) {
  117.         char *p = pathname;
  118.  
  119.         /* Parse list of paths; directories seperated by colon */
  120.         while (*paths && *paths != ':') *p++ = *paths++;
  121.         *p++ = '\0'; 
  122.  
  123.         /* Append recursively */
  124.         (VOID) io_path(pathname, pos);
  125.  
  126.         /* Access next path if available */
  127.         if (*paths) paths++;
  128.         }
  129.         return IO_NO_ERROR;
  130.     }
  131.     else
  132.         return IO_UNKNOWN_PATH;
  133.     }
  134.  
  135.     /* Check that the last character is a slash if not add it */
  136.     if (pname[plen - 1] != DIRSEPCHAR) {
  137.     pname[plen++] = DIRSEPCHAR;
  138.     pname[plen] = '\0';
  139.     }
  140.  
  141.     /* Check if the path has already been defined */
  142.     for (i = 0; i <= psp; i++)
  143.     if (STREQ(paths[i], pname)) return IO_PATH_DEFINED;
  144.     
  145.     /* Check if space is available on path stack */
  146.     if (psp + 1 == PATHSSIZE) return IO_TOO_MANY_PATHS;
  147.  
  148.     /* Make space for the new path */
  149.     psp = psp + 1;
  150.     
  151.     /* Check where the path should be appended */
  152.     if (pos == IO_PATH_FIRST) {
  153.     for (i = psp; i > 0; i--) paths[i] = paths[i - 1];
  154.     pos = 0;
  155.     }
  156.     else pos = psp;
  157.  
  158.     /* Add path string att position given */
  159.     paths[pos] = strcpy((char *) malloc((unsigned) plen + 1), pname);
  160.  
  161.     return IO_NO_ERROR;
  162. }
  163.  
  164. VOID io_flush()
  165. {
  166.     /* Flush any waiting output */
  167.     (VOID) fflush(stdout);    
  168.  
  169.     /* Close all open files if not end of input stream */
  170.     if (io_not_eof()) {
  171.  
  172.     /* Close all files but lowest */
  173.     while (io_infsp > 0) (VOID) close(io_infstack[io_infsp--] -> fd);
  174.  
  175.     /* Close lowest file on file stack if not tty */
  176.     if (!isatty(io_infstack[io_infsp] -> fd))
  177.         (VOID) close(io_infstack[io_infsp--] -> fd);
  178.     }
  179. }
  180.  
  181. INT io_infile(fname)
  182.     CSTR fname;            /* Pointer to file name to open as input */
  183. {
  184.     CHAR filename[FILENAMESIZE];
  185.     INT i, j;
  186.     INT fd;
  187.     
  188.     /* Check for standard input as source */
  189.     if (fname == STDIN) {
  190.  
  191.     /* Check if space is available on file stack */
  192.     if (io_infsp + 1 == INFSTACKSIZE) return IO_TOO_MANY_FILES;
  193.  
  194.     /* Push standard input as source onto the file buffer stack */
  195.     io_infsp = io_infsp + 1;
  196.     io_infstack[io_infsp] -> fd = STDIN;
  197.     io_infstack[io_infsp] -> bufp = 0;
  198.     io_infstack[io_infsp] -> cc = 0;
  199.     io_infstack[io_infsp] -> fn = NIL;
  200.     io_infstack[io_infsp] -> ln = 1;
  201.     return IO_NO_ERROR;
  202.     }
  203.  
  204.     /* Expand the file name using the path stack and try opening the file */
  205.     for (i = 0; i <= psp; i++) {
  206.  
  207.     /* Build the new file name using a path */
  208.     (VOID) strcpy(filename, paths[i]);
  209.     (VOID) strcpy(filename + strlen(paths[i]), fname);
  210.  
  211.     /* Check if this file has already been loaded */
  212.     for (j = 0; j <= infsp; j++)
  213.         if (STREQ(infiles[j], filename)) return IO_FILE_INCLUDED;
  214.  
  215.     /* Try opening the file */
  216.     fd = open(filename, O_RDONLY);
  217.  
  218.     /* If no errors then save the file name and return file descriptor */
  219.     if (fd != -1) {
  220.  
  221.         /* Check if space is available on file stack */
  222.         if (io_infsp + 1 == INFSTACKSIZE) return IO_TOO_MANY_FILES;
  223.  
  224.         /* Push file onto the file buffer stack and use it as source */
  225.         infsp = infsp + 1;
  226.         infiles[infsp] = strcpy((char *) malloc((unsigned) strlen(filename) + 1), filename);
  227.         io_infstack[++io_infsp] -> fd = fd;
  228.         io_infstack[io_infsp] -> bufp = 0;
  229.         io_infstack[io_infsp] -> cc = 0;
  230.         io_infstack[io_infsp] -> fn = infiles[infsp];
  231.         io_infstack[io_infsp] -> ln = 1;
  232.         return fd;
  233.     }
  234.     }
  235.  
  236.     /* The file was not available so return error */
  237.     return IO_UNKNOWN_FILE;
  238. }
  239.  
  240.  
  241. INT io_fillbuf()
  242. {
  243.     BOOL nonblocking;
  244.  
  245.     /* Check io consistency and foreground task input only */
  246.     if (io_eof() || tp != foreground) error_fatal(0);
  247.     
  248.     /* Flush any waiting output if filling buffer from a terminal */
  249.     if (isatty(io_infstack[io_infsp] -> fd)) (VOID) fflush(stdout);
  250.  
  251.     /* Check for multi-tasking input operation */
  252.     if (tp != ((TASK) tp -> queue.succ)) {
  253.     (VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, FNDELAY); 
  254.     tp -> status = IOWAITING;
  255.     nonblocking = TRUE;
  256.     }
  257.     else
  258.     nonblocking = FALSE;
  259.     
  260.     /* Allow multi-tasking during waiting for input */
  261.     for (;;) {
  262.  
  263.     /* Try reading a block from the current input stream */
  264.     if ((io_infstack[io_infsp] -> cc = read(io_infstack[io_infsp] -> fd,
  265.                         io_infstack[io_infsp] -> buf,
  266.                         BUFSIZE)) > 0) {
  267.  
  268.         /* Restore to non-blocking input from file and foreground */
  269.         if (nonblocking) {
  270.         (VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, 0);
  271.         spush(foreground, TASK);
  272.         doresume();
  273.         tp -> status = RUNNING;
  274.         }
  275.  
  276.         /* Initiate the buffer pointer and return the first character */
  277.         io_infstack[io_infsp] -> bufp = 0;
  278.         return io_getchar();
  279.     }
  280.  
  281.     /* Did the read operation result in an end of file */
  282.     if (io_infstack[io_infsp] -> cc == 0 && errno != EWOULDBLOCK) {
  283.  
  284.         /* Set back the file mode to synchronous and close the file */
  285.         if (nonblocking) {
  286.         (VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, 0);
  287.         spush(foreground, TASK);
  288.         doresume();
  289.         tp -> status = RUNNING;
  290.         }
  291.         (VOID) close(io_infstack[io_infsp--] -> fd); 
  292.         
  293.         /* Check if end of input source */
  294.         if (io_eof()) return IO_EOF;
  295.  
  296.         /* Get character from previous file buffer */
  297.         return io_getchar();
  298.     }
  299.  
  300.     /* Run forth level tasks while waiting for input */
  301.     if (tp == foreground) dodetach(); else doinner();
  302.     
  303.     /* Check if the task for empty, i.e., only the foreground */
  304.     if (tp == foreground && tp == ((TASK) tp -> queue.succ)) {
  305.         (VOID) fcntl(io_infstack[io_infsp] -> fd, F_SETFL, 0); 
  306.         nonblocking = FALSE;
  307.     }
  308.     
  309.     /* Allow user extension of the io wait loop */
  310.     io_dispatch();
  311.     }
  312. }
  313.  
  314. VOID io_skip(skpchr)
  315.     CHAR skpchr;        /* Skip character */
  316. {
  317.     CHAR c;
  318.  
  319.     /* Skip all characters until skip termination character or end of file */
  320.     while (io_not_eof()) {
  321.     c = io_getchar();
  322.     if (c == '\n') io_newline();
  323.     if (c == skpchr) return;
  324.     }
  325. }
  326.  
  327. VOID io_scan(buf, brkchr)
  328.     CSTR buf;            /* Pointer to scan buffer */
  329.     CHAR brkchr;        /* Break character */
  330. {
  331.     CHAR c;
  332.     
  333.     /* Initiate buffer as null string */
  334.     *buf = '\0';
  335.  
  336.     /* Check for scanning until white space or special break character */
  337.     if (brkchr == ' ') {
  338.  
  339.     /* While not white space or end of file */
  340.     while (io_not_eof()) {
  341.         c = io_getchar();
  342.         if (c == '\n') io_newline();
  343.         if (ISSPACE(c)) break;
  344.         *buf++ = c;
  345.     }
  346.     }
  347.     else {
  348.  
  349.     /* While not the break character or end of file */
  350.     while (io_not_eof()) {
  351.         c = io_getchar();
  352.         if (c == '\n') io_newline();
  353.         if (c == brkchr) break;
  354.         *buf++ = c;
  355.     }
  356.     }
  357.     
  358.     /* End the string and return */
  359.     *buf = '\0';
  360.     return;
  361. }
  362.  
  363. VOID io_skipspace()
  364. {
  365.     CHAR c;
  366.     
  367.     /* Skip all white spaces */
  368.     while (io_not_eof()) {
  369.     c = io_getchar();
  370.     if (c == '\n') io_newline();
  371.     if (!ISSPACE(c)) break;
  372.     }
  373.     
  374.     /* Step back the buffer pointer */
  375.     if (io_not_eof()) io_infstack[io_infsp] -> bufp -= 1;
  376. }
  377.  
  378. VOID io_initiate(banner)
  379.     CSTR banner;        /* Initiate application message */
  380. {
  381.     INT i;
  382.  
  383.     /* Assign output and error file */
  384.     io_outf = stdout;
  385.     io_errf = stderr;
  386.  
  387.     /* Print banner and add initial paths */
  388.     (VOID) printf(banner);
  389.     (VOID) io_path("$PWD", IO_PATH_LAST);
  390.     (VOID) io_path("$HOME", IO_PATH_LAST);
  391.     (VOID) io_path("$TILEPATH", IO_PATH_LAST);
  392.  
  393.     /* Allocate file buffers */
  394.     for (i = 0; i < INFSTACKSIZE; i++) {
  395.     io_infstack[i] = (INFILE_BUFFER) malloc((unsigned) sizeof(file_buffer));
  396.     if (io_infstack[i] == NIL) {
  397.         (VOID) fprintf(io_errf, "io: cannot allocate file buffers\n");
  398.         exit(0);
  399.     }
  400.     }
  401.  
  402. }    
  403.     
  404. VOID io_finish()
  405. {
  406.     /* Flush any waiting output */
  407.     (VOID) fflush(stdout);    
  408.  
  409.     /* Close all open files */
  410.     while (io_not_eof()) (VOID) close(io_infstack[io_infsp--] -> fd);
  411. }
  412.  
  413.